import datetime
import json
import sys
import time
import random
import re

import requests

from absl import flags

from selenium import webdriver

from coin.exchange.base.kr_rest.auth_base import AuthKey

FLAGS = flags.FLAGS

flags.DEFINE_string("key_file", None, "Path of output key_file which has authentication token.")

flags.DEFINE_string("userpass_key_file",
                    None,
                    "Path of json file which has owner/username/password fields.")

flags.DEFINE_string("kakaotalk_crawler_url", "http://localhost:10101/", "kakaotalk_crawler_url")


def _get_upbit_otp(kakaotalk_email, kakaotalk_password, kakaotalk_crawler_url):
  headers = {'content-type': 'application/json'}

  payload = {
      "method": "get_latest_upbit_channel_msg",
      "params": [kakaotalk_email, kakaotalk_password],
      "jsonrpc": "2.0",
      "id": 0,
  }

  try:
    response = requests.post(kakaotalk_crawler_url, data=json.dumps(payload),
                             headers=headers).json()
    otp = re.findall('\([0-9]+\)', response['result'])[-1][1:-1]
  except Exception:
    raise Exception('Cannot get a upbit OTP')

  return otp


class LocalStorage(object):
  def __init__(self, driver):
    assert type(driver) == webdriver.Chrome
    self.driver = driver

  def set(self, key, value):
    self.driver.execute_script("window.localStorage.setItem('{}',{})".format(
        key, json.dumps(value)))

  def get(self, key=None):
    if key:
      return self.driver.execute_script("return window.localStorage.getItem('{}')".format(key))
    else:
      return self.driver.execute_script("""
        var items = {}, ls = window.localStorage;
        for (var i = 0, k; i < ls.length; i++)
          items[k = ls.key(i)] = ls.getItem(k);
        return items;
        """)

  def remove(self, key):
    self.driver.execute_script("window.localStorage.removeItem('{}');".format(key))

  def clear(self):
    self.driver.execute_script("window.localStorage.clear();")


def _create_driver():
  driver = webdriver.Chrome('chromedriver')
  driver.implicitly_wait(3)
  driver.get('https://upbit.com')
  driver.implicitly_wait(8)
  driver.get("https://upbit.com/signin")
  driver.set_page_load_timeout(60)

  return driver


class UpbitChromeDriver(object):
  def __init__(self):
    self.driver = _create_driver()

  def login_with_kakaotalk_otp(self,
                               kakaotalk_email,
                               kakaotalk_password,
                               kakaotalk_crawler_url='http://localhost:10101/'):
    driver = self.driver
    driver.implicitly_wait(10)
    # Check login for 24 hour.
    driver.find_element_by_xpath('//*[@id="root"]/div/div/div[3]/section/article/div/a').click()
    time.sleep(1)
    # Click a button "Login with KakaoTalk ID".
    driver.find_element_by_xpath('//*[@id="root"]/div/div/div[3]/section/article/a').click()

    driver.implicitly_wait(10)
    # Input email and password.
    email = driver.find_element_by_xpath('//*[@id="email"]')
    password = driver.find_element_by_xpath('//*[@id="password"]')
    email.send_keys(kakaotalk_email)
    password.send_keys(kakaotalk_password)

    driver.set_page_load_timeout(180)
    driver.implicitly_wait(3)
    time.sleep(random.randint(5, 8))
    driver.find_element_by_xpath('//*[@id="btn_login"]').click()

    otp = _get_upbit_otp(kakaotalk_email, kakaotalk_password, kakaotalk_crawler_url)

    # Input OTP and wait.
    otp_textbox = driver.find_element_by_xpath(
        '//*[@id="root"]/div/div/div[3]/section/article/span[2]/input')
    otp_textbox.send_keys(otp)
    driver.find_element_by_xpath('//*[@id="root"]/div/div/div[3]/section/article/a').click()
    time.sleep(4)

  def get_key(self, owner=None):
    storage = LocalStorage(self.driver)
    obj = storage.get("bitmochi")
    obj = json.loads(obj)
    key = AuthKey(owner=owner,
                  key_name="view+trade",
                  access_key=obj["sessions"]["tokens"]["access_key"],
                  secret_key=obj["sessions"]["tokens"]["secret_key"],
                  generated=str(datetime.datetime.utcnow()),
                  generated_human=str(datetime.datetime.now()))
    return key

  def quit(self):
    if self.driver is not None:
      self.driver.quit()
      self.driver = None


def main():
  with open(FLAGS.userpass_key_file) as f:
    userpass = json.load(f)

  assert 'owner' in userpass
  assert 'username' in userpass
  assert 'password' in userpass

  try:
    driver = UpbitChromeDriver()
    driver.login_with_kakaotalk_otp(userpass['username'],
                                    userpass['password'],
                                    FLAGS.kakaotalk_crawler_url)
    key = driver.get_key(userpass['owner'])
  except Exception:
    raise
  finally:
    driver.quit()

  print(key.as_json_str())
  if FLAGS.key_file is not None:
    erroneous_key_file = []
    for key_file in FLAGS.key_file.split(","):
      try:
        print(key_file)
        key.save_file(key_file)
      except Exception:
        print("failed to save to", key_file)
        erroneous_key_file.append(key_file)

    if len(erroneous_key_file):
      raise Exception('Failed to save to: ' + repr(erroneous_key_file))


if __name__ == '__main__':
  FLAGS(sys.argv)
  main()
